﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using System.Runtime.Serialization.Formatters;
using System.Threading;
using System.Windows;

namespace MishraReader
{
    public static class SingleInstanceHelper
    {
        private const string ChannelNameSuffix = "SingeInstanceIPCChannel";
        private const string Delimiter = ":";
        private const string IpcProtocol = "ipc://";
        private const string RemoteServiceName = "SingleInstanceApplicationService";
        private static IpcServerChannel _channel;
        private static Mutex _singleInstanceMutex;

        public static void Cleanup()
        {
            if (_singleInstanceMutex != null)
            {
                _singleInstanceMutex.Close();
                _singleInstanceMutex = null;
            }

            if (_channel != null)
            {
                ChannelServices.UnregisterChannel(_channel);
                _channel = null;
            }
        }

        public static bool InitializeAsFirstInstance()
        {
            var applicationIdentifier = "MishraReader" + Environment.UserName;

            var channelName = String.Concat(applicationIdentifier, Delimiter, ChannelNameSuffix);

            // Create mutex based on unique application Id to check if this is the first instance of the application. 
            bool firstInstance;
            _singleInstanceMutex = new Mutex(true, applicationIdentifier, out firstInstance);
            if (firstInstance)
            {
                CreateRemoteService(channelName);
            }
            else
            {
                SignalFirstInstance(channelName);
            }

            return firstInstance;
        }

        private static void CreateRemoteService(string channelName)
        {
            var serverProvider = new BinaryServerFormatterSinkProvider {TypeFilterLevel = TypeFilterLevel.Full};
            IDictionary props = new Dictionary<string, string>();

            props["name"] = channelName;
            props["portName"] = channelName;
            props["exclusiveAddressUse"] = "false";

            _channel = new IpcServerChannel(props, serverProvider);

            ChannelServices.RegisterChannel(_channel, true);

            var remoteService = new IPCRemoteService();
            RemotingServices.Marshal(remoteService, RemoteServiceName);
        }

        private static void SignalFirstInstance(string channelName)
        {
            var secondInstanceChannel = new IpcClientChannel();
            ChannelServices.RegisterChannel(secondInstanceChannel, true);

            var remotingServiceUrl = IpcProtocol + channelName + "/" + RemoteServiceName;

            // Obtain a reference to the remoting service exposed by the server i.e the first instance of the application
            var firstInstanceRemoteServiceReference = (IPCRemoteService)RemotingServices.Connect(typeof(IPCRemoteService), remotingServiceUrl);

            if (firstInstanceRemoteServiceReference != null)
            {
                firstInstanceRemoteServiceReference.InvokeFirstInstance();
            }
        }

        private class IPCRemoteService : MarshalByRefObject
        {
            public override object InitializeLifetimeService()
            {
                return null;
            }

            public void InvokeFirstInstance()
            {
                if (Application.Current != null)
                {
                    // TODO refonte
                    /* Application.Current.Dispatcher.BeginInvoke(new Action(() =>
                        (Application.Current.MainWindow as MishraReaderWindow).HandleNotificationClick()));*/
                }
            }
        }
    }
}